/*
*Copyright (c) Nikhil Jain.
*Project ICARUS, communications and 
*artificial intelligence.
*/



/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
 */
package javadrone.client.simulation;

//~--- non-JDK imports --------------------------------------------------------

import com.lti.civil.CaptureException;

import javadrone.Drone;
import javadrone.RemoteImage;
import javadrone.Server;

import javadrone.agent.ExtendedAgent;

import javadrone.client.DroneClient;
import javadrone.client.access.ImageProvider;
import javadrone.client.access.ImageQueue;
import javadrone.client.simulator.ClientGUI;

import javadrone.command.Command;
import javadrone.command.CommandExecutor;
import javadrone.command.ExecutionStatus;
import javadrone.command.ExecutorException;

import javadrone.remotepackage.RemoteBootPackage;

import javadrone.statedata.BootData;

import simbad.demo.Demo;

import simbad.sim.CameraSensor;
import simbad.sim.RobotFactory;

//~--- JDK imports ------------------------------------------------------------

import java.awt.image.BufferedImage;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import java.rmi.RemoteException;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;

import javax.vecmath.Vector3d;

/**
 *
 * @author Nikzzay
 */
public class VirtualBotSimulator extends BotSimulator {
    private ClientGUI    cg;
    private BotAgentDemo env;

    public VirtualBotSimulator(Drone commandDrone, CommandExecutor ce, int queueSize) throws CaptureException {
        super(commandDrone, ce, queueSize);
    }

    @Override
    public ExecutionStatus boot(RemoteBootPackage rbp) {
        BotAgentDemo bad = new BotAgentDemo();

        env = bad;
        System.out.println(rbp);
        rbp.fill(env);
        bad.bot.attach(imageQueue);
        attachImageProvider(bad.bot);
        cg = new ClientGUI(getEnvironment(), rbp.backgroundMode());
        cg.startSimulation();
        setAlive(true);
        bootFlag = BootData.BootState.BootFlag.BOOT_SUCCESS;

        return ExecutionStatus.BOOTSTRAP;
    }

    @Override
    public ExecutionStatus kill() {
        setAlive(false);
        cg.setVisible(false);

        return ExecutionStatus.KILLED;
    }

    @Override
    public Demo getEnvironment() {
        return env;
    }

    @Override
    public ExecutionStatus translateBy(Vector3d translate) {
        env.bot.setTranslationalVelocity(translate);

        return ExecutionStatus.SUCCESS;
    }

    @Override
    public ExecutionStatus rotateBy(Vector3d rotate) {
        env.bot.setRotationalVelocity(rotate);

        return ExecutionStatus.SUCCESS;
    }

    @Override
    public Vector3d getCoords() {
        return env.bot.getCoordinates();
    }

    @Override
    public Vector3d getAngles() {
        return env.bot.getRotationAngles();
    }

    public class BotAgentDemo extends Demo {
        Robot bot;

        public BotAgentDemo() {
            bot = new Robot(new Vector3d(0, 0, 0), "BotAgentRobot");
            add(bot);
        }

        public class Robot extends ExtendedAgent implements ImageProvider {
            private CameraSensor  camera;
            private BufferedImage cameraImage;
            private ImageQueue    iQ;
            private boolean       startStreamFlag;

            public Robot(Vector3d position, String name) {
                super(position, name);
                camera      = RobotFactory.addCameraSensor(Robot.this);
                cameraImage = camera.createCompatibleImage();
            }

            @Override
            public void start() {
                startStreamFlag = true;
            }

            @Override
            public void stop() {
                startStreamFlag = false;
            }

            @Override
            public void attach(ImageQueue iQ) {
                this.iQ = iQ;
            }

            /** Perform one step of Agent's Behavior */
            @Override
            public void performBehavior() {
                try {
                    if (startStreamFlag) {
                        camera.copyVisionImage(cameraImage);

                        byte[] bytes = null;

                        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                            ImageIO.write(cameraImage, "jpeg", os);
                            bytes = os.toByteArray();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        iQ.add(new RemoteImage(bytes, System.currentTimeMillis() + DroneClient.TIMEDIFF()));
                    }

                    System.out.println("Waiting for next command..." + commandDrone.commandsInQueue());

                    if (collisionDetected()) {
                        System.out.println("Collided...");
                        ce.raiseCollisionFlag();

                        return;
                    }

                    Command nextCommand = commandDrone.takeCommand();

                    System.out.println("Command executed...");
                    nextCommand.execute(ce);
                } catch (InterruptedException | ExecutorException | RemoteException ex) {
                    Logger.getLogger(BotSimulator.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
